package com.vinjogames.util;

import java.util.ArrayList;
import java.util.List;

import android.graphics.PointF;

import com.vinjogames.entities.Game;
import com.vinjogames.entities.GameObject;
import com.vinjogames.entities.Player;
import com.vinjogames.entities.Unit;
import com.vinjogames.gfx.Camera;
import com.vinjogames.util.AILogic.DesiredShot;


public class AIDriver {

	private Game mGame;
	private Player mPlayer;
	private Player mOpposingPlayer;
	
	private Unit selectedUnit;
	private GameObject enemy;
	private DesiredShot shot;
	
	private static final int ACTION_IDLE = 0;
	private static final int ACTION_MOVING = 1;
	private static final int ACTION_AIMING = 2;
	private static final int ACTION_SHOOTING = 3;
	
	private int AI_State = ACTION_IDLE;
	
	private AIDriver(){};

	private static class AIDriverHolder {
		public static final AIDriver instance = new AIDriver();
	}

	public static AIDriver getInstance(){
		return AIDriverHolder.instance;
	}
	
	public void LoadGame(Game game, Player aiPlayer, Player humanPlayer){
		mGame = game;
		mPlayer = aiPlayer;
		mOpposingPlayer = humanPlayer;
	}
	
	public void tick() throws Exception{
		if(isAIPlayersTurn()){
			
			if(!Preferences.isDebug()) {//Disable AI Driver unless in debug mode
				mGame.endTurn(null);
				return;
			}
			
			if(selectedUnit != null && AI_State != ACTION_SHOOTING)
				Camera.getInstance().setFocusedObject(selectedUnit);
			
			switch(AI_State){
			case ACTION_IDLE:
				selectedUnit = mGame.getNextUnit();
				
				if(selectedUnit.getPlayer() != mPlayer){
					return;  //Check if its my unit
				}
				
				if(selectedUnit.hasFired()){//or has moved
					//select another one?
					Logger.log("AI: Going IDLE");
					AI_State = ACTION_IDLE;
					enemy = null;
					shot = null;
					selectedUnit = null;
					mGame.endTurn(null);
				}else{
					AI_State = ACTION_MOVING;
					Logger.log("AI: Going MOVING");
				}
				
				break;
			case ACTION_MOVING:
				if(!mGame.moveUnit(null)){
					AI_State = ACTION_AIMING;
					Logger.log("AI: Going SHOOTING");
				}
				
				//TODO:  getDesiredPlace
				//       try to move to that place, if at that place or out of movement, start shooting
				//       Find general area, between 1-2, random, (wiggle back and forth) to avoid getting shot
				
				if(selectedUnit.getMovementUsed() >= selectedUnit.getMaxMovement()){
					AI_State = ACTION_AIMING;
					Logger.log("AI: Going AIMING");
				}
				break;
			case ACTION_AIMING:
				if(!selectedUnit.hasFired()){
					
					if(enemy == null){
						enemy = GetEnemyUnit(mGame.getUnits());
					}
					if(shot == null){
						selectedUnit.enterAttackMode();
						shot = GenerateShot(selectedUnit, enemy);
					}
					if(selectedUnit.getCurrentForce() < shot.power){
						selectedUnit.setCurrentForce(selectedUnit.getCurrentForce() + 0.1f);
					}
					
					if(selectedUnit.getGun().getAngle() < shot.angle){
						selectedUnit.getGun().setAngle(selectedUnit.getGun().getAngle() + 0.5f);
					}

					if((selectedUnit.getCurrentForce() >= shot.power) && selectedUnit.getGun().getAngle() >= shot.angle){
						selectedUnit.setCurrentForce(shot.power);
						selectedUnit.getGun().setAngle(shot.angle);
						AI_State = ACTION_SHOOTING;
						Logger.log("AI: Going SHOOTING");
					}				
				}
				//move cannon a couple of degrees towards desired shot every tick
				//when at desired shot, change state to shooting
				break;
			case ACTION_SHOOTING:
				// if gamestate == idle or gamestate != moving || something
				//When game is done animating shot, need to change AI_state to idle
				if(selectedUnit.hasFired() && mGame.getGameState() == Game.IDLE){
					AI_State = ACTION_IDLE;
					Logger.log("AI: Going IDLE");
				}else{
					mGame.shootUnit(null);
				}
					
				break;
			default:
				//Do nothing
					break;
			}			
		}
	}
	
	private GameObject GetEnemyUnit(Unit[] units){
		for(Unit u: units){
			if(u != null && u.checkActiveStatus()){
				if(u.getPlayer() != mPlayer){
					return u;
				}
			}
		}
		
		//Unable to find valid enemy unit
		//Try to target base instead
		return mOpposingPlayer.getBase();
	}
	
	private DesiredShot GenerateShot(Unit currentUnit, GameObject enemyUnit){
		
		if(enemyUnit == null || !enemyUnit.checkActiveStatus()){
			Logger.log("Could not find valid enemy unit to target");
			return null;
		}
		
		List<PointF> tempList = new ArrayList<PointF>();
		tempList.add(enemyUnit.getLocation());
		DesiredShot shot = mPlayer.myAI.calculateShot(currentUnit.getLocation(), tempList);
		
		if(currentUnit.getDirection() != shot.faceRight) {
			currentUnit.switchDirection();
		}
		
		return shot;
	}
	
	private boolean isAIPlayersTurn() {
		if(!(mGame.getCurrentPlayer() == null)) {
			return !mGame.isLocalPlayersTurn() && mGame.getCurrentPlayer().getType() == GameConVars.PLAYER_AI;
		}
		else
			return false;
	}
	
	public int getState(){ return AI_State; }
}
